home *** CD-ROM | disk | FTP | other *** search
/ QuickTime 2.0 Developer Kit / QuickTime 2.0 Developer Kit.iso / pc / windows / qtw_201 / setup / samples / browser / browser.c next >
Encoding:
C/C++ Source or Header  |  1994-12-19  |  24.9 KB  |  822 lines

  1.  
  2. // ---------------------------------------------------------------------
  3. //
  4. // BROWSER.C    - QuickTime for Windows
  5. //
  6. //                Version 1.0
  7. //
  8. //                (c) Copyright 1988-1994 Apple Computer, Inc. All Rights Reserved.
  9. //
  10. // ---------------------------------------------------------------------
  11.  
  12.  
  13. #define OEMRESOURCE
  14. #include <windows.h>
  15. #include <qtw.h>
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <common.h>
  20. #include "browser.hr"
  21.  
  22.  
  23. // Constants
  24. // ---------
  25. #define MAX_THUMBNAILS 64
  26. #define THUMBNAIL_INDENT 20
  27. #define THUMBNAIL_INDENT_BOTTOM 40
  28. #define THUMBNAIL_HEIGHT 60
  29. #define THUMBNAIL_WIDTH 80
  30. #define BEVEL_OUTDENT 6
  31. #define DESC_TEXT_HEIGHT 12
  32. #define REPEAT_CLICK 1
  33. #define STRIP_SHIFT 2
  34.  
  35.  
  36. // Functions
  37. // ---------
  38. long FAR PASCAL __export WndProc (HWND, UINT, WPARAM, LPARAM);
  39. static BOOL NEAR MyBuildThumbNails (HWND, LPSTR);
  40. static BOOL NEAR MyBuildThumbNailPoster (HWND, int);
  41. static LONG NEAR MyClickDown (HWND, int, int);
  42. static LONG NEAR MyClickUp (HWND, int, int);
  43. static LONG NEAR MyDoubleClick (HWND, int, int);
  44. static LONG NEAR MyPaintBrowser (HWND);
  45. static BOOL NEAR MyShowMovie (HWND, int);
  46. static LONG NEAR MySizeBrowser (HWND, int, int);
  47.  
  48.  
  49. // Globals
  50. // -------
  51. static char szAppName[] = "BROWSER";
  52. static char szWaiting[] = "Initializing Browser...";
  53. static char szMovie[MAX_THUMBNAILS][_MAX_FNAME];
  54. static char szDesc[MAX_THUMBNAILS][COMMON_STRING_MAX];
  55. static Movie mMovie;
  56. static MovieController mcController;
  57. static PicHandle phPoster[MAX_THUMBNAILS];
  58. static RECT rcMovie, rcThumbNail, rcThumb, rcTopStrip, rcBotStrip, rcRArrow, rcLArrow, rcDesc;
  59. static int iStrip, iThumbNail, cThumbNails, cThumbsShown;
  60. static HINSTANCE hInstance;
  61. static HBITMAP hbmRArrow, hbmLArrow, hbmRArrowD, hbmLArrowD, hbmStrip;
  62. static BOOL bInLArrow, bInRArrow, bInThumbNail;
  63.  
  64.  
  65. // WinMain
  66. // ---------------------------------------------------------------------
  67. int PASCAL WinMain (HINSTANCE hInst, HINSTANCE hPrevInstance,
  68.                     LPSTR lpszCmdLine, int nCmdShow)
  69. {
  70.     HWND hWnd;
  71.     RECT rcDesktop, rcBrowser;
  72.     MSG msg;
  73.     WNDCLASS wc;
  74.  
  75.     hInstance = hInst;
  76.  
  77.     // Register our special class
  78.  
  79.     if (!hPrevInstance) {
  80.         wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
  81.         wc.lpfnWndProc = WndProc;
  82.         wc.cbClsExtra = 0;
  83.         wc.cbWndExtra = DLGWINDOWEXTRA;
  84.         wc.hInstance = hInstance;
  85.         wc.hIcon = LoadIcon (hInstance, szAppName);
  86.         wc.hCursor = LoadCursor (NULL, IDC_ARROW);
  87.         wc.hbrBackground = (HBRUSH) GetStockObject (LTGRAY_BRUSH);
  88.         wc.lpszMenuName = NULL;
  89.         wc.lpszClassName = szAppName;
  90.         RegisterClass (&wc);
  91.     }
  92.  
  93.     // Load some bitmaps
  94.  
  95.     hbmRArrow  = LoadBitmap ( hInstance, "Rbtnup");
  96.     hbmLArrow  = LoadBitmap ( hInstance, "Lbtnup");
  97.     hbmRArrowD = LoadBitmap ( hInstance, "Rbtndn");
  98.     hbmLArrowD = LoadBitmap ( hInstance, "Lbtndn");
  99.     hbmStrip   = LoadBitmap (hInstance, "Strip");
  100.  
  101.     // Create the dialog
  102.  
  103.     hWnd = CreateDialog (hInstance, szAppName, 0, NULL);
  104.     GetWindowRect (hWnd, &rcBrowser);
  105.     GetWindowRect (GetDesktopWindow (), &rcDesktop);
  106.     SetWindowPos (hWnd, 0,
  107.         rcDesktop.left + (((rcDesktop.right - rcDesktop.left)
  108.         - (rcBrowser.right - rcBrowser.left)) / 2),
  109.         rcDesktop.top + (((rcDesktop.bottom - rcDesktop.top)
  110.         - (rcBrowser.bottom - rcBrowser.top)) / 2),
  111.         rcBrowser.right - rcBrowser.left,
  112.         rcBrowser.bottom - rcBrowser.top, SWP_NOZORDER);
  113.  
  114.     // Establish links to QuickTime for Windows
  115.  
  116.     if (QTInitialize (NULL)) {
  117.         MessageBox (NULL, "QTInitialize failure", szAppName, MB_OK);
  118.         return 0;
  119.     }
  120.  
  121.     // Allocate memory required for playing movies
  122.  
  123.     if (EnterMovies ()) {
  124.         MessageBox (NULL, "EnterMovies failure", szAppName, MB_OK);
  125.         return 0;
  126.     }
  127.  
  128.     // Create a movie controller
  129.  
  130.     mcController = NewMovieController (NULL, &rcBrowser, mcNotVisible, hWnd);
  131.  
  132.     // Display the dialog
  133.  
  134.     ShowWindow (hWnd, nCmdShow);
  135.  
  136.     // Build posters for each thumbnail
  137.  
  138.     if (! MyBuildThumbNails (hWnd, lpszCmdLine)) {
  139.         return 0;
  140.     }
  141.  
  142.     // Show the first movie
  143.  
  144.     MyShowMovie (hWnd, 0);
  145.  
  146.     // Process all Windows messages
  147.  
  148.     while (GetMessage (&msg, NULL, 0, 0)) {
  149.         TranslateMessage (&msg);
  150.         DispatchMessage (&msg);
  151.     }
  152.  
  153.     // Cut links to QuickTime
  154.  
  155.     DisposeMovieController (mcController);
  156.     DisposeMovie (mMovie);
  157.  
  158.     for (iThumbNail = 0; iThumbNail < cThumbNails; iThumbNail++) {
  159.         DisposePicture (phPoster[iThumbNail]);
  160.     }
  161.  
  162.     ExitMovies ();
  163.     QTTerminate ();
  164.  
  165.     // Delete the Windows bitmaps we used
  166.  
  167.     DeleteObject (hbmRArrow);
  168.     DeleteObject (hbmLArrow);
  169.     DeleteObject (hbmRArrowD);
  170.     DeleteObject (hbmLArrowD);
  171.     DeleteObject (hbmStrip);
  172.  
  173.     // Return to Windows
  174.  
  175.     return msg.wParam;
  176.  
  177. }
  178.  
  179.  
  180. // WndProc
  181. // ---------------------------------------------------------------------
  182. long FAR PASCAL __export WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  183. {
  184.  
  185.     // Drive the movie controller
  186.  
  187.     MCIsPlayerMessage (mcController, hWnd, message, wParam, lParam);
  188.  
  189.     // Act on the message
  190.  
  191.     switch (message) {
  192.  
  193.         // All Done!
  194.  
  195.         case WM_DESTROY:
  196.             PostQuitMessage (0);
  197.             return 0;
  198.  
  199.         // Background erase
  200.  
  201.         case WM_ERASEBKGND:
  202.             return (bInLArrow || bInRArrow)? TRUE : DefWindowProc (hWnd, message, wParam, lParam);
  203.  
  204.         // Double click
  205.  
  206.         case WM_LBUTTONDBLCLK:
  207.             return MyDoubleClick (hWnd, (int) LOWORD (lParam), (int) HIWORD (lParam));
  208.  
  209.         // Click down
  210.  
  211.         case WM_LBUTTONDOWN:
  212.             return MyClickDown (hWnd, (int) LOWORD (lParam), (int) HIWORD (lParam));
  213.  
  214.         // Click up
  215.  
  216.         case WM_LBUTTONUP:
  217.             return MyClickUp (hWnd, (int) LOWORD (lParam), (int) HIWORD (lParam));
  218.  
  219.         // Paint
  220.  
  221.         case WM_PAINT:
  222.             return MyPaintBrowser (hWnd);
  223.  
  224.         // Resize
  225.  
  226.         case WM_SIZE:
  227.             return MySizeBrowser (hWnd, (int) LOWORD (lParam), (int) HIWORD (lParam));
  228.  
  229.         // Timer (repeat click)
  230.  
  231.         case WM_TIMER:
  232.             return MyClickDown (hWnd, 0, 0);
  233.  
  234.     }
  235.  
  236.     // Return to Windows
  237.  
  238.     return DefWindowProc (hWnd, message, wParam, lParam);
  239.  
  240. }
  241.  
  242.  
  243. // MyBuildThumbNails
  244. // ---------------------------------------------------------------------
  245. static BOOL NEAR MyBuildThumbNails (HWND hWnd, LPSTR lpszCmdLine)
  246. {
  247.     FILE* hList;
  248.     HDC hdc;
  249.     int iNameLen;
  250.     DWORD dw;
  251.     RECT rcClient;
  252.     char szList[_MAX_FNAME];
  253.     char szBuffer[COMMON_STRING_MAX];
  254.     char* p;
  255.  
  256.     // Get name of browser list
  257.  
  258.     lstrcpy (szList, lpszCmdLine);
  259.     if (strlen (szList) == 0) {
  260.         GetModuleFileName (hInstance, szList, sizeof (szList));
  261.         p = strrchr (szList, '.');
  262.         *p = 0;
  263.         strcat (szList, ".lst");
  264.     }
  265.  
  266.     // Attempt to open browser list
  267.  
  268.     if ((hList = fopen (szList, "r")) == NULL) {
  269.         MessageBox (0, "Nothing to do!", szAppName, MB_ICONEXCLAMATION);
  270.         return FALSE;
  271.     }
  272.  
  273.     // Issue "waiting" message
  274.  
  275.     hdc = GetDC (hWnd);
  276.     SetBkMode (hdc, TRANSPARENT);
  277.     dw = GetTextExtent (hdc, szWaiting, strlen (szWaiting));
  278.     GetClientRect (hWnd, &rcClient);
  279.     TextOut (hdc, rcClient.left + ((rcClient.right - rcClient.left - LOWORD (dw)) / 2),
  280.         rcClient.top + ((rcClient.bottom - rcClient.top - HIWORD (dw)) / 2),
  281.         szWaiting, strlen (szWaiting));
  282.     ReleaseDC (hWnd, hdc);
  283.  
  284.     // Parse browser list
  285.  
  286.     memset (szBuffer, 0, sizeof (szBuffer));
  287.     while (fgets (szBuffer, sizeof (szBuffer), hList) != NULL) {
  288.  
  289.         // Eliminate trailing new line character
  290.  
  291.         iNameLen = strlen( szBuffer);
  292.         if ((iNameLen == sizeof( szBuffer)) ||
  293.             (szBuffer[iNameLen-1] == 0x0A))
  294.             szBuffer[strlen (szBuffer) - 1] = 0;
  295.         else szBuffer[iNameLen] = 0;
  296.  
  297.         // Only process so many
  298.  
  299.         if (cThumbNails == MAX_THUMBNAILS)
  300.             break;
  301.  
  302.         // Extract movie name and build its bitmap
  303.  
  304.         p = strchr (szBuffer, ' ');
  305.         *p = 0;
  306.         strcpy (szMovie[cThumbNails], szBuffer);
  307.         if (! MyBuildThumbNailPoster (hWnd, cThumbNails))
  308.             continue;
  309.  
  310.         // Extract description (use movie name if missing)
  311.  
  312.         p = szBuffer + strlen (szBuffer) + 1;
  313.         while (p) {
  314.             if ((*p != ' ') && (*p != '\t')) break;
  315.             ++p;
  316.         }
  317.         if (strlen (p) > 0)
  318.             strcpy (szDesc[cThumbNails], p);
  319.         else strcpy (szDesc[cThumbNails], szMovie[cThumbNails]);
  320.  
  321.         // Keep going until we've found them all
  322.  
  323.         memset (szBuffer, 0, sizeof (szBuffer));
  324.         cThumbNails++;
  325.     }
  326.  
  327.     // All done!
  328.  
  329.     fclose (hList);
  330.     InvalidateRect (hWnd, NULL, TRUE);
  331.     return TRUE;
  332.  
  333. }
  334.  
  335.  
  336. // MyBuildThumbNailPoster
  337. // ---------------------------------------------------------------------
  338. static BOOL NEAR MyBuildThumbNailPoster (HWND hWnd, int iThumbNail)
  339. {
  340.     MovieFile mfMovie;
  341.     Movie mMovie;
  342.  
  343.     // Instantiate the movie
  344.  
  345.     if (OpenMovieFile (szMovie[iThumbNail], &mfMovie, OF_READ) != noErr) {
  346.         return FALSE;
  347.     }
  348.     NewMovieFromFile (&mMovie, mfMovie, NULL, NULL, 0, NULL);
  349.     CloseMovieFile (mfMovie);
  350.  
  351.     // Get its poster pict
  352.  
  353.     phPoster[iThumbNail] = GetMoviePosterPict (mMovie);
  354.     DisposeMovie (mMovie);
  355.  
  356.     // Return to caller
  357.  
  358.     return (phPoster[iThumbNail] != NULL);
  359. }
  360.  
  361.  
  362. // MyClickDown
  363. // ---------------------------------------------------------------------
  364. static LONG NEAR MyClickDown (HWND hWnd, int x, int y)
  365. {
  366.     POINT pt;
  367.     LOGFONT lf;
  368.     HFONT hFont, hFontOld;
  369.     HBITMAP hbmOld;
  370.     HDC hdc, hdcMem;
  371.     DWORD dw;
  372.     UINT uiDelay;
  373.     int i;
  374.  
  375.     // Get location of click
  376.  
  377.     pt.x = x, pt.y = y;
  378.  
  379.     // Get ready to paint
  380.  
  381.     hdc = GetDC (hWnd);
  382.     SetBkMode (hdc, TRANSPARENT);
  383.     hdcMem = CreateCompatibleDC (hdc);
  384.  
  385.     // Did we click the left arrow?
  386.  
  387.     if ((iThumbNail > 0) && (PtInRect (&rcLArrow, pt) || bInLArrow)) {
  388.         bInLArrow = TRUE;
  389.         hbmOld = SelectObject (hdcMem, hbmLArrowD);
  390.         BitBlt (hdc, rcLArrow.left, rcLArrow.top,
  391.             (rcLArrow.right - rcLArrow.left),
  392.             (rcLArrow.bottom - rcLArrow.top),
  393.             hdcMem, 0, 0, SRCCOPY);
  394.         SelectObject (hdcMem, hbmOld);
  395.         iThumbNail = max (0, iThumbNail - 1);
  396.         iStrip -= STRIP_SHIFT;
  397.         InvalidateRect (hWnd, &rcRArrow, FALSE);
  398.         InvalidateRect (hWnd, &rcTopStrip, FALSE);
  399.         InvalidateRect (hWnd, &rcThumbNail, FALSE);
  400.         InvalidateRect (hWnd, &rcBotStrip, FALSE);
  401.         UpdateWindow (hWnd);
  402.         SystemParametersInfo (SPI_GETKEYBOARDDELAY, 0, &uiDelay, 0);
  403.         SetTimer (hWnd, REPEAT_CLICK, uiDelay, NULL);
  404.     }
  405.  
  406.     // Did we click the right arrow?
  407.  
  408.     if (((iThumbNail + cThumbsShown) < cThumbNails)
  409.         && (PtInRect (&rcRArrow, pt) || bInRArrow)) {
  410.         bInRArrow = TRUE;
  411.         hbmOld = SelectObject (hdcMem, hbmRArrowD);
  412.         BitBlt (hdc, rcRArrow.left, rcRArrow.top,
  413.             (rcRArrow.right - rcRArrow.left),
  414.             (rcRArrow.bottom - rcRArrow.top),
  415.             hdcMem, 0, 0, SRCCOPY);
  416.         SelectObject (hdcMem, hbmOld);
  417.         iThumbNail = min (cThumbNails - cThumbsShown, iThumbNail + 1);
  418.         iStrip += STRIP_SHIFT;
  419.         InvalidateRect (hWnd, &rcLArrow, FALSE);
  420.         InvalidateRect (hWnd, &rcTopStrip, FALSE);
  421.         InvalidateRect (hWnd, &rcThumbNail, FALSE);
  422.         InvalidateRect (hWnd, &rcBotStrip, FALSE);
  423.         UpdateWindow (hWnd);
  424.         SystemParametersInfo (SPI_GETKEYBOARDDELAY, 0, &uiDelay, 0);
  425.         SetTimer (hWnd, REPEAT_CLICK, uiDelay, NULL);
  426.     }
  427.  
  428.     // Did we click the thumbnails?
  429.  
  430.     else if (PtInRect (&rcThumbNail, pt)) {
  431.         i = (x - rcThumbNail.left) / THUMBNAIL_WIDTH;
  432.         if ((i + iThumbNail) >= cThumbNails)
  433.             MessageBeep (MB_ICONEXCLAMATION);
  434.         else {
  435.             bInThumbNail = TRUE;
  436.             rcThumb = rcThumbNail;
  437.             rcThumb.left += (i * THUMBNAIL_WIDTH);
  438.             rcThumb.right = min (rcThumb.left + THUMBNAIL_WIDTH, rcThumbNail.right);
  439.             InvertRect (hdc, &rcThumb);
  440.             memset (&lf, 0, sizeof (lf));
  441.             lf.lfHeight = MulDiv (DESC_TEXT_HEIGHT, GetDeviceCaps (hdc, LOGPIXELSY), 72);
  442.             lf.lfWeight = FW_LIGHT;
  443.             lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
  444.             lf.lfPitchAndFamily = FF_SWISS;
  445.             strcpy (lf.lfFaceName, "Arial");
  446.             hFont = CreateFontIndirect (&lf);
  447.             hFontOld = SelectObject (hdc, hFont);
  448.             dw = GetTextExtent (hdc, szDesc[iThumbNail+i], strlen (szDesc[iThumbNail+i]));
  449.             TextOut (hdc, rcDesc.left + ((rcDesc.right - rcDesc.left - LOWORD (dw)) / 2),
  450.                 rcDesc.top + ((rcDesc.bottom - rcDesc.top - HIWORD (dw)) / 2),
  451.                 szDesc[iThumbNail+i], strlen (szDesc[iThumbNail+i]));
  452.             SelectObject (hdc, hFontOld);
  453.             DeleteObject (hFont);
  454.         }
  455.     }
  456.  
  457.     // Done painting
  458.  
  459.     DeleteDC (hdcMem);
  460.     ReleaseDC (hWnd, hdc);
  461.  
  462.     // Capture the mouse
  463.  
  464.     SetCapture (hWnd);
  465.  
  466.     // Return to Windows
  467.  
  468.     return 0;
  469.  
  470. }
  471.  
  472.  
  473. // MyClickUp
  474. // ---------------------------------------------------------------------
  475. static LONG NEAR MyClickUp (HWND hWnd, int x, int y)
  476. {
  477.     HDC hdc;
  478.  
  479.     // Get ready to paint
  480.  
  481.     hdc = GetDC (hWnd);
  482.  
  483.     // Did we click an arrow?
  484.  
  485.     if (bInLArrow || bInRArrow) {
  486.         bInLArrow = FALSE;
  487.         bInRArrow = FALSE;
  488.         InvalidateRect (hWnd, &rcLArrow, TRUE);
  489.         InvalidateRect (hWnd, &rcRArrow, TRUE);
  490.         UpdateWindow (hWnd);
  491.         KillTimer (hWnd, REPEAT_CLICK);
  492.     }
  493.  
  494.     // Did we click the thumbnails?
  495.  
  496.     else if (bInThumbNail) {
  497.         bInThumbNail = FALSE;
  498.         InvertRect (hdc, &rcThumb);
  499.         InvalidateRect (hWnd, &rcDesc, TRUE);
  500.     }
  501.  
  502.     // Done painting
  503.  
  504.     ReleaseDC (hWnd, hdc);
  505.  
  506.     // Release the mouse capture
  507.  
  508.     ReleaseCapture ();
  509.  
  510.     // Return to Windows
  511.  
  512.     return 0;
  513.  
  514. }
  515.  
  516.  
  517. // MyDoubleClick
  518. // ---------------------------------------------------------------------
  519. static LONG NEAR MyDoubleClick (HWND hWnd, int x, int y)
  520. {
  521.     POINT pt;
  522.     int i;
  523.  
  524.     // Get location of click
  525.  
  526.     pt.x = x, pt.y = y;
  527.  
  528.     // Did we click the thumbnails?
  529.  
  530.     if (PtInRect (&rcThumbNail, pt)) {
  531.         i = (x - rcThumbNail.left) / THUMBNAIL_WIDTH;
  532.         if ((i + iThumbNail) < cThumbNails)
  533.             MyShowMovie (hWnd, iThumbNail + i);
  534.     }
  535.  
  536.     // Return to Windows
  537.  
  538.     return 0;
  539.  
  540. }
  541.  
  542.  
  543. // MyPaintBrowser
  544. // ---------------------------------------------------------------------
  545. static LONG NEAR MyPaintBrowser (HWND hWnd)
  546. {
  547.     RECT rcPoster;
  548.     HDC hdcMem;
  549.     PAINTSTRUCT ps;
  550.     HPEN hpenLight, hpenShadow, hpenOld;
  551.     HBITMAP hbmOld;
  552.     BITMAP bm;
  553.     int i;
  554.  
  555.     // Create the pens we'll need to draw the bevels
  556.  
  557.     hpenLight = CreatePen (PS_SOLID, 1, RGB (255, 255, 255));
  558.     hpenShadow = CreatePen (PS_SOLID, 1, RGB (128, 128, 128));
  559.  
  560.     // Prepare to paint
  561.  
  562.     if (BeginPaint (hWnd, &ps) == 0)
  563.         return 0;
  564.  
  565.     // Draw bevel around movie
  566.  
  567.     hpenOld = SelectObject (ps.hdc, hpenLight);
  568.     MoveTo (ps.hdc, rcMovie.left - BEVEL_OUTDENT, rcMovie.bottom + BEVEL_OUTDENT);
  569.     LineTo (ps.hdc, rcMovie.left - BEVEL_OUTDENT, rcMovie.top - BEVEL_OUTDENT);
  570.     LineTo (ps.hdc, rcMovie.right + BEVEL_OUTDENT, rcMovie.top - BEVEL_OUTDENT);
  571.     MoveTo (ps.hdc, rcMovie.left - BEVEL_OUTDENT + 1, rcMovie.bottom + BEVEL_OUTDENT - 1);
  572.     LineTo (ps.hdc, rcMovie.left - BEVEL_OUTDENT + 1, rcMovie.top - BEVEL_OUTDENT + 1);
  573.     LineTo (ps.hdc, rcMovie.right + BEVEL_OUTDENT - 1, rcMovie.top - BEVEL_OUTDENT + 1);
  574.     MoveTo (ps.hdc, rcMovie.left - 1, rcMovie.bottom);
  575.     LineTo (ps.hdc, rcMovie.right, rcMovie.bottom);
  576.     LineTo (ps.hdc, rcMovie.right, rcMovie.top - 1);
  577.     SelectObject (ps.hdc, hpenOld);
  578.  
  579.     hpenOld = SelectObject (ps.hdc, hpenShadow);
  580.     MoveTo (ps.hdc, rcMovie.left - BEVEL_OUTDENT, rcMovie.bottom + BEVEL_OUTDENT);
  581.     LineTo (ps.hdc, rcMovie.right + BEVEL_OUTDENT, rcMovie.bottom + BEVEL_OUTDENT);
  582.     LineTo (ps.hdc, rcMovie.right + BEVEL_OUTDENT, rcMovie.top - BEVEL_OUTDENT);
  583.     MoveTo (ps.hdc, rcMovie.left - BEVEL_OUTDENT + 1, rcMovie.bottom + BEVEL_OUTDENT - 1);
  584.     LineTo (ps.hdc, rcMovie.right + BEVEL_OUTDENT - 1, rcMovie.bottom + BEVEL_OUTDENT - 1);
  585.     LineTo (ps.hdc, rcMovie.right + BEVEL_OUTDENT - 1, rcMovie.top - BEVEL_OUTDENT + 1);
  586.     MoveTo (ps.hdc, rcMovie.left - 1, rcMovie.bottom - 1);
  587.     LineTo (ps.hdc, rcMovie.left - 1, rcMovie.top - 1);
  588.     LineTo (ps.hdc, rcMovie.right, rcMovie.top - 1);
  589.     SelectObject (ps.hdc, hpenOld);
  590.  
  591.     // Draw bevel around thumbnails
  592.  
  593.     hpenOld = SelectObject (ps.hdc, hpenLight);
  594.     MoveTo (ps.hdc, rcThumbNail.left - BEVEL_OUTDENT, rcBotStrip.bottom + BEVEL_OUTDENT);
  595.     LineTo (ps.hdc, rcThumbNail.left - BEVEL_OUTDENT, rcTopStrip.top - BEVEL_OUTDENT);
  596.     LineTo (ps.hdc, rcThumbNail.right + BEVEL_OUTDENT, rcTopStrip.top - BEVEL_OUTDENT);
  597.     MoveTo (ps.hdc, rcThumbNail.left - BEVEL_OUTDENT + 1, rcBotStrip.bottom + BEVEL_OUTDENT - 1);
  598.     LineTo (ps.hdc, rcThumbNail.left - BEVEL_OUTDENT + 1, rcTopStrip.top - BEVEL_OUTDENT + 1);
  599.     LineTo (ps.hdc, rcThumbNail.right + BEVEL_OUTDENT - 1, rcTopStrip.top - BEVEL_OUTDENT + 1);
  600.     SelectObject (ps.hdc, hpenOld);
  601.  
  602.     hpenOld = SelectObject (ps.hdc, hpenShadow);
  603.     MoveTo (ps.hdc, rcThumbNail.left - BEVEL_OUTDENT, rcBotStrip.bottom + BEVEL_OUTDENT);
  604.     LineTo (ps.hdc, rcThumbNail.right + BEVEL_OUTDENT, rcBotStrip.bottom + BEVEL_OUTDENT);
  605.     LineTo (ps.hdc, rcThumbNail.right + BEVEL_OUTDENT, rcTopStrip.top - BEVEL_OUTDENT);
  606.     MoveTo (ps.hdc, rcThumbNail.left - BEVEL_OUTDENT + 1, rcBotStrip.bottom + BEVEL_OUTDENT - 1);
  607.     LineTo (ps.hdc, rcThumbNail.right + BEVEL_OUTDENT - 1, rcBotStrip.bottom + BEVEL_OUTDENT - 1);
  608.     LineTo (ps.hdc, rcThumbNail.right + BEVEL_OUTDENT - 1, rcTopStrip.top - BEVEL_OUTDENT + 1);
  609.     SelectObject (ps.hdc, hpenOld);
  610.  
  611.     // Bitblt the arrows
  612.  
  613.     hdcMem = CreateCompatibleDC (ps.hdc);
  614.     if (iThumbNail > 0) {
  615.         hbmOld = SelectObject (hdcMem, hbmLArrow);
  616.         BitBlt (ps.hdc, rcLArrow.left, rcLArrow.top,
  617.             (rcLArrow.right - rcLArrow.left),
  618.             (rcLArrow.bottom - rcLArrow.top),
  619.             hdcMem, 0, 0, SRCCOPY);
  620.         SelectObject (ps.hdc, hbmOld);
  621.     }
  622.     if ((iThumbNail + cThumbsShown) < cThumbNails) {
  623.         hbmOld = SelectObject (hdcMem, hbmRArrow);
  624.         BitBlt (ps.hdc, rcRArrow.left, rcRArrow.top,
  625.             (rcRArrow.right - rcRArrow.left),
  626.             (rcRArrow.bottom - rcRArrow.top),
  627.             hdcMem, 0, 0, SRCCOPY);
  628.         SelectObject (ps.hdc, hbmOld);
  629.     }
  630.     DeleteDC (hdcMem);
  631.  
  632.     // Clip out poster area to help drawing logic
  633.  
  634.     GetObject (hbmStrip, sizeof (bm), &bm);
  635.     IntersectClipRect (ps.hdc,
  636.         rcThumbNail.left, rcThumbNail.top - bm.bmHeight,
  637.         rcThumbNail.right, rcThumbNail.bottom + bm.bmHeight);
  638.  
  639.     // Draw each poster in the thumbnail area
  640.  
  641.     rcPoster = rcThumbNail;
  642.     for (i = iThumbNail; i < cThumbNails; i++) {
  643.         rcPoster.right = rcPoster.left + THUMBNAIL_WIDTH;
  644.         DrawPicture (ps.hdc, phPoster[i], &rcPoster, NULL);
  645.         if ((rcPoster.left += THUMBNAIL_WIDTH) >= rcThumbNail.right)
  646.             break;
  647.     }
  648.  
  649.     // Blank out any unused poster slots
  650.  
  651.     rcPoster.right = rcThumbNail.right;
  652.     FillRect (ps.hdc, &rcPoster, (HBRUSH) GetStockObject (WHITE_BRUSH));
  653.  
  654.     // Bitblt the film strips
  655.  
  656.     hdcMem = CreateCompatibleDC (ps.hdc);
  657.     hbmOld = SelectObject (hdcMem, hbmStrip);
  658.     BitBlt (ps.hdc, rcTopStrip.left, rcTopStrip.top,
  659.         (rcTopStrip.right - rcTopStrip.left),
  660.         (rcTopStrip.bottom - rcTopStrip.top),
  661.         hdcMem, iStrip, 0, SRCCOPY);
  662.     BitBlt (ps.hdc, rcBotStrip.left, rcBotStrip.top,
  663.         (rcBotStrip.right - rcBotStrip.left),
  664.         (rcBotStrip.bottom - rcBotStrip.top),
  665.         hdcMem, iStrip, 0, SRCCOPY);
  666.     SelectObject (hdcMem, hbmOld);
  667.     DeleteDC (hdcMem);
  668.  
  669.     // Done painting, return to Windows
  670.  
  671.     EndPaint (hWnd, &ps);
  672.     DeleteObject (hpenLight);
  673.     DeleteObject (hpenShadow);
  674.     return 0;
  675.  
  676. }
  677.  
  678.  
  679. // MyShowMovie
  680. // ---------------------------------------------------------------------
  681. static BOOL NEAR MyShowMovie (HWND hWnd, int iThumbNail)
  682. {
  683.     MovieFile mfMovie;
  684.     POINT ptMovie;
  685.     RECT rcClient, rcBrowser, rcWash;
  686.     int xDelta, yDelta, iDepth;
  687.     BOOL bDouble;
  688.     HDC hdc;
  689.  
  690.     // Dispose of any prior movie
  691.  
  692.     if (mMovie) {
  693.         MCRemoveMovie (mcController);
  694.         DisposeMovie (mMovie);
  695.     }
  696.  
  697.     // Instantiate the movie
  698.  
  699.     if (OpenMovieFile (szMovie[iThumbNail], &mfMovie, OF_READ) != noErr) {
  700.         return FALSE;
  701.     }
  702.     NewMovieFromFile (&mMovie, mfMovie, NULL, NULL, 0, NULL);
  703.     CloseMovieFile (mfMovie);
  704.  
  705.     // Calculate where to put the controller
  706.  
  707.     for (bDouble = TRUE;;) {
  708.         GetMovieBox (mMovie, &rcMovie);
  709.         GetClientRect (hWnd, &rcClient);
  710.         rcClient.bottom = rcTopStrip.top - (2 * THUMBNAIL_INDENT);
  711.         OffsetRect (&rcMovie, -rcMovie.left, -rcMovie.top);
  712.         hdc = GetDC (hWnd);
  713.         iDepth = GetDeviceCaps (hdc, BITSPIXEL) * GetDeviceCaps (hdc, PLANES);
  714.         ReleaseDC (hWnd, hdc);
  715.         if (bDouble && (iDepth > 8))
  716.             rcMovie.right *= 2, rcMovie.bottom *= 2;
  717.         OffsetRect (&rcMovie, (rcClient.right - rcMovie.right) / 2,
  718.             (rcClient.bottom - rcMovie.bottom) / 2);
  719.         xDelta = (rcClient.left + THUMBNAIL_INDENT) - rcMovie.left;
  720.         yDelta = (rcClient.top + THUMBNAIL_INDENT) - rcMovie.top;
  721.         GetWindowRect (hWnd, &rcBrowser);
  722.         if (xDelta > 0)
  723.             rcBrowser.left -= xDelta, rcBrowser.right += xDelta;
  724.         else if (yDelta > 0)
  725.             rcBrowser.top -= yDelta, rcBrowser.bottom += yDelta;
  726.         else break;
  727.         if ((rcBrowser.left < 0) || (rcBrowser.top < 0)) {
  728.             bDouble = FALSE;
  729.             continue;
  730.         }
  731.         SetWindowPos (hWnd, 0, rcBrowser.left, rcBrowser.top,
  732.             rcBrowser.right - rcBrowser.left,
  733.             rcBrowser.bottom - rcBrowser.top, SWP_NOZORDER | SWP_SHOWWINDOW);
  734.     }
  735.  
  736.     // Associate the movie and the controller
  737.  
  738.     ptMovie.x = rcMovie.left;
  739.     ptMovie.y = rcMovie.top;
  740.     MCSetMovie (mcController, mMovie, hWnd, ptMovie);
  741.  
  742.     // Reposition the controller
  743.  
  744.     MCPositionController (mcController, &rcMovie,
  745.         NULL, mcTopLeftMovie + mcScaleMovieToFit);
  746.     MCSetVisible (mcController, TRUE);
  747.     MCGetControllerBoundsRect (mcController, &rcMovie);
  748.     SetRectEmpty (&rcClient);
  749.     MCDoAction (mcController, mcActionSetGrowBoxBounds, (LPVOID) &rcClient);
  750.  
  751.     // Action!
  752.  
  753.     SetMovieActive (mMovie, TRUE);
  754.     GetClientRect (hWnd, &rcWash);
  755.     rcWash.bottom = rcDesc.bottom;
  756.     InvalidateRect (hWnd, &rcWash, TRUE);
  757.     MCDoAction (mcController, mcActionSetFlags, (LPVOID) mcFlagsUseWindowPalette);
  758.     MCDoAction (mcController, mcActionSetKeysEnabled, (LPVOID) TRUE);
  759.  
  760.     // Update the window title
  761.  
  762.     SetWindowText (hWnd, szDesc[iThumbNail]);
  763.  
  764.     // Return to caller
  765.  
  766.     return TRUE;
  767. }
  768.  
  769.  
  770. // MySizeBrowser
  771. // ---------------------------------------------------------------------
  772. static LONG NEAR MySizeBrowser (HWND hWnd, int cx, int cy)
  773. {
  774.     BITMAP bm;
  775.  
  776.     // Calculate the location of the left scroll arrow
  777.  
  778.     GetObject (hbmLArrow, sizeof (bm), &bm);
  779.     rcLArrow.left = bm.bmWidth / 2;
  780.     rcLArrow.right = rcLArrow.left + bm.bmWidth;
  781.     rcLArrow.top = (cy - (THUMBNAIL_HEIGHT + THUMBNAIL_INDENT_BOTTOM))
  782.         + ((THUMBNAIL_HEIGHT - bm.bmHeight) / 2);
  783.     rcLArrow.bottom = rcLArrow.top + bm.bmHeight;
  784.  
  785.     // Calculate the location of the right scroll arrow
  786.  
  787.     rcRArrow.left = cx - ((3 * bm.bmWidth) / 2);
  788.     rcRArrow.right = rcRArrow.left + bm.bmWidth;
  789.     rcRArrow.top = (cy - (THUMBNAIL_HEIGHT + THUMBNAIL_INDENT_BOTTOM))
  790.         + ((THUMBNAIL_HEIGHT - bm.bmHeight) / 2);
  791.     rcRArrow.bottom = rcRArrow.top + bm.bmHeight;
  792.  
  793.     // Calculate thumb nail area
  794.  
  795.     rcThumbNail.left = rcLArrow.right + (bm.bmWidth / 4) + BEVEL_OUTDENT;
  796.     rcThumbNail.right = rcRArrow.left - (bm.bmWidth / 4) - BEVEL_OUTDENT;
  797.     rcThumbNail.top = cy - (THUMBNAIL_HEIGHT + THUMBNAIL_INDENT_BOTTOM);
  798.     rcThumbNail.bottom = cy - THUMBNAIL_INDENT_BOTTOM;
  799.     cThumbsShown = (rcThumbNail.right - rcThumbNail.left) / THUMBNAIL_WIDTH;
  800.  
  801.     // Calculate top and bottom film strip areas
  802.  
  803.     GetObject (hbmStrip, sizeof (bm), &bm);
  804.     rcTopStrip = rcThumbNail;
  805.     rcTopStrip.bottom = rcTopStrip.top;
  806.     rcTopStrip.top -= bm.bmHeight;
  807.     rcBotStrip = rcThumbNail;
  808.     rcBotStrip.top = rcBotStrip.bottom;
  809.     rcBotStrip.bottom += bm.bmHeight;
  810.  
  811.     // Calculate description area
  812.  
  813.     rcDesc = rcTopStrip;
  814.     rcDesc.bottom = rcTopStrip.top;
  815.     rcDesc.top = rcDesc.bottom - (3 * DESC_TEXT_HEIGHT);
  816.  
  817.     // Return to Windows
  818.  
  819.     return 0;
  820.  
  821. }
  822.